Skip to content

feat: add streaming client-side CSV/GeoJSON/shapefile bulk export pipeline - #80

Merged
elizabetheonoja-art merged 3 commits into
Utility-Protocol:mainfrom
real-venus:feat/bulk-export-pipeline
Jun 25, 2026
Merged

feat: add streaming client-side CSV/GeoJSON/shapefile bulk export pipeline#80
elizabetheonoja-art merged 3 commits into
Utility-Protocol:mainfrom
real-venus:feat/bulk-export-pipeline

Conversation

@real-venus

Copy link
Copy Markdown
Contributor

Client-Side Bulk Export Pipeline — CSV / GeoJSON / Shapefile (#60)

Closes #60

What's included

File Responsibility
src/types/export.ts Config, filters, progress, events, and bounds: 10k rows/chunk, 100-chunk cap (1M rows), 50 MB flush threshold, 100 MB fallback limit, 6-decimal coordinate precision, 2-chunk prefetch window.
src/utils/ndjsonParser.ts Streaming NDJSON parser — pipes the body through native DecompressionStream (gzip), falling back to the pako polyfill; splits on newlines and yields parsed rows as they arrive.
src/utils/formatTransformers.ts RFC 4180 CSV escaping/quoting, GeoJSON Point Feature (coordinates truncated to 6 dp), and shapefile record extraction.
src/utils/shapefileWriter.ts + src/utils/zip.ts EPSG:4326 Point .shp/.shx/.dbf/.prj writer, bundled into a STORED .zip (with a CRC-32 implementation).
src/utils/fileWriter.ts FileWriter abstraction — streams to disk via FileSystemWritableFileStream, or accumulates a Blob download with a memory-pressure warning when the API is unavailable.
src/services/exportPipeline.ts Orchestrator: sliding 2-chunk prefetch window, memory guard (flush past 50 MB), client-side filtering, per-format output framing, progress events, and cancellation.
src/hooks/useExportProgress.ts Reduces pipeline events (chunkStart/chunkComplete/warning/complete/cancelled/error) into a single ExportProgress for the UI.
src/components/panels/ExportDialog.tsx Format dropdown, schema-driven column multiselect, filter builder, progress bar + cancel.
src/app/export/page.tsx Host route for the dialog.
tests/unit/* + tests/e2e/export.spec.ts Transformer/parser/zip/shapefile/pipeline unit tests, plus a Playwright spec that triggers an export and verifies the downloaded CSV row count.

…eline (Utility-Protocol#60)

Streams filtered resource data from the REST API in chunked, gzipped NDJSON
requests, transforms rows into the target format, and writes the result to disk
via the File System Access API (Blob download fallback) without holding the
whole dataset in memory.

- types/export.ts: config, filters, progress, events and bounds (10k rows/chunk,
  100-chunk cap, 50MB flush threshold, 6-decimal coord precision)
- utils/ndjsonParser.ts: streaming NDJSON parser over DecompressionStream with a
  pako polyfill fallback
- utils/formatTransformers.ts: RFC 4180 CSV, GeoJSON Point Feature (truncated
  coords), shapefile record extraction
- utils/shapefileWriter.ts + utils/zip.ts: EPSG:4326 Point .shp/.shx/.dbf/.prj
  bundled into a STORED zip (with CRC32)
- utils/fileWriter.ts: FS Access WritableStream writer + in-memory Blob fallback
  with memory-pressure warning
- services/exportPipeline.ts: orchestrator with 2-chunk sliding prefetch window,
  memory guard, client-side filtering and progress events
- hooks/useExportProgress.ts: reduces pipeline events into progress state
- components/panels/ExportDialog.tsx: format selector, column picker, filter
  builder, progress bar + cancel
- app/export: host route for the dialog
- unit tests (transformers, ndjson, zip/shapefile, pipeline) + Playwright export
  spec verifying downloaded row count
…ds (Utility-Protocol#60)

The export dialog fetches from NEXT_PUBLIC_API_URL (cross-origin from the dev
server), so the Playwright route mocks now return permissive CORS headers;
without them the browser blocked the responses and the schema never loaded,
leaving the Export button disabled until the job timed out.

Also force the Blob download fallback in the spec (headless Chromium may expose
showSaveFilePicker, whose native dialog can never appear and would hang the
export), and drop the forbidden Accept-Encoding header from chunk requests since
the browser manages it automatically.
@elizabetheonoja-art

Copy link
Copy Markdown
Contributor

@real-venus ci failed

@real-venus

Copy link
Copy Markdown
Contributor Author

@real-venus ci failed

Now I am working on it.

…tility-Protocol#60)

The app's service worker intercepts fetches once it controls the page, and
Playwright's page.route does not see service-worker-originated requests. The
mocked /api/resources endpoints were therefore bypassed and hit the real
(absent) network, failing with net::ERR_FAILED so the schema never loaded and
the export hung until timeout. Blocking the service worker for this spec lets
the route mocks intercept every request. Verified: full E2E suite 22/22 green.
@elizabetheonoja-art
elizabetheonoja-art merged commit 507ebaa into Utility-Protocol:main Jun 25, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Client-Side CSV/GeoJSON Bulk Export Pipeline with Streaming Chunked NDJSON and File System Access API

2 participants